#include "Dwarf.Unmanaged.MPI.h"

//Pointers to the factory functions.
static DLLParseArguments pDLLParseArguments;
static DLLUsage pDLLUsage;
static DLLStart pDLLStart;
static DLLStop pDLLStop;

//Pointers to dll.
static HINSTANCE hInstDll;

// Constructor that init strings.
Settings :: Settings()
{
    inputFile = new char[BUFFER_SIZE];
    resultFile = new char[BUFFER_SIZE];
	profileFile = new char[BUFFER_SIZE];

    inputFile[0] = resultFile[0] = profileFile[0] ='\0';
}

// Constructor that dispose strings.
Settings :: ~Settings()
{
    delete inputFile;
    delete resultFile;
	delete profileFile;
}

// Get one line from stream.
static void getNextLine(char* str, FILE* file) 
{
	short count = 0;
	char ch = ' ';    

    while (!feof(file) && (ch == ' ' || ch == '\n' || ch == '\r')) 
    {
        ch = (char)getc(file);
	}

    str[count] = ch;
	while (!feof(file) && ch != '\r' && ch != '\n' && ch != ' ') 
    {
		str[++count] = (ch = (char)getc(file));
	}
	
	str[count] = '\0';
}

// Parse input file into solver's structures.
int Settings::parseConfigFile(Solver* slasolver) 
{
    FILE *file;

    // Open the file to read from.
    if( fopen_s(&file, inputFile, "rb")) 
    {
        printf("Can't open configfile!\r\n");
        (pDLLUsage)();

        return -1;
    }

    char *str = new char[BUFFER_SIZE];

    //Get number of rows.
    getNextLine(str, file);
    slasolver->rowNum = atoi(str);

    //Get number of non-zero values.
    getNextLine(str, file);
    slasolver->valNum = atoi(str);

    //Init arrays.
    slasolver->val = new double[slasolver->valNum];
    slasolver->col_ind = new int[slasolver->valNum];
    slasolver->row_ptr = new int[slasolver->rowNum + 1];
    slasolver->vector = new double[slasolver->rowNum];
    slasolver->result = new double[slasolver->rowNum];

    //get val array of CRS
    int i = 0;
    while(!feof(file) && i < slasolver->valNum)
    {
        getNextLine(str, file);
        slasolver->val[i] = atof(str);

        i ++;
    }  

    //get col_ind array of CRS
    i = 0;
    while(!feof(file) && i < slasolver->valNum)
    {
        getNextLine(str, file);
        slasolver->col_ind[i] = atoi(str);

        i ++;
    }  

    //get row_ptr array of CRS
    i = 0;
    while(!feof(file) && i < slasolver->rowNum + 1)
    {
        getNextLine(str, file);
        slasolver->row_ptr[i] = atoi(str);

        i ++;
    }  

    //get vector
    i = 0;
    while(!feof(file) && i < slasolver->rowNum)
    {
        getNextLine(str, file);
        slasolver->vector[i] = atof(str);

        i ++;
    } 

    delete str;

    //Dispose input file.
    fclose(file);

    return 0;
}

// Init variables, parse cli params and input file.
int Settings::init(int argc, char** argv, Solver *slasolver) 
{
    
    // Load the dll into the address space
	//fix: C4706
    //if (!(hInstDll = LoadLibraryA("CliTools"))) 
    //{
	hInstDll = LoadLibraryA("CliTools");
	if(!hInstDll)
	{
        printf("Error while loading CliTools.dll.");

        return -1;
    }

    // Retrieve a pointer to the factory function
    pDLLParseArguments = 
        (DLLParseArguments) GetProcAddress(hInstDll, "parseArguments");

    pDLLUsage =
        (DLLUsage) GetProcAddress(hInstDll, "usage");

    pDLLStart = 
        (DLLStart) GetProcAddress(hInstDll, "start");

    pDLLStop = 
        (DLLStop) GetProcAddress(hInstDll, "stop");

    //Parse cli params.
    if ((pDLLParseArguments)(argc, argv, &inputFile, &profileFile,  &resultFile)) 
    {
        FreeLibrary(hInstDll); 
        return -1;
    }
    
    //Parse input file.
    if (parseConfigFile(slasolver)) 
    {
        FreeLibrary(hInstDll); 
        return -1;
    }

    //Write settings if it's needed.
    writeSettings(slasolver);	
    return 0;
}

// Start the time count.
void Settings::start() 
{
    (pDLLStart)();
}

// Problem results output.
void Settings::finish(Solver *slasolver)
{
    double time;
    (pDLLStop)(&time);

    //Release dll.
    FreeLibrary(hInstDll);//*/

    printf("\r\n");
    printf("Clock time (sec): %.8f \r\n", time);  

        FILE* outputResult = 0;
        FILE* outputProfile = 0;

		if( fopen_s(&outputProfile, profileFile , "wb")) 
		{
			printf("Can't create profile file!\r\n");            
			fclose(outputProfile);
			return;
		}

		if( fopen_s(&outputResult, resultFile , "wb")) 
		{
			printf("Can't create result file!\r\n");   
			fclose(outputResult);
			return;
		}
            

        fprintf(outputProfile, "#Dwarfname:%s\r\n",DWARF_NAME);

        char tmpbuf[BUFFER_SIZE];
        _tzset();
        
        _strdate_s( tmpbuf, BUFFER_SIZE );
        fprintf(outputProfile, "#Time: %s ",tmpbuf);

        _strtime_s( tmpbuf, BUFFER_SIZE );
        fprintf(outputProfile, "%s \r\n",tmpbuf);

        fprintf(outputProfile, "#Matrix Row Number: %i\r\n", slasolver->rowNum);
        fprintf(outputProfile, "#Result time (sec): %.8f\r\n", time);  
		fprintf(outputResult,"#Result domain:\r\n");
        for (int i = 0; i < slasolver->rowNum; i ++) 
        {
			if ((i != 0) && (i % 20 ) == 0 ) fprintf(outputResult, "\r\n");
            fprintf(outputResult,"%0.8f ", slasolver->result[i]);
            
        }
        fprintf(outputResult,"\r\n");

        fprintf(outputProfile, "#eof");//*/

        fclose(outputProfile);
        fclose(outputResult);
	
}

// Write settings.
void Settings::writeSettings(Solver *slasolver)
{
    // Write general settings.
    printf("Kernel settings summary : \r\n");
    printf("Dwarf name              : %s \r\n", DWARF_NAME);
    printf("Matrix Row Number       : %d \r\n", slasolver->rowNum);
    printf("Inputfile               : %s \r\n", inputFile);
    printf("Profilefile             : %s \r\n", profileFile);
    printf("Outputfile              : %s \r\n", resultFile);    
    printf("\r\n");   
}